package com.xhl.doeverything.redis;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//


import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author xionghuilong
 * @description: redis分布式锁
 * @date 2021/12/3 14:12
 */
@Slf4j
@Component
public class RedisDistributedLock extends AbstractDistributedLock {
    private static final String UNLOCK_LUA = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then     return redis.call(\"del\",KEYS[1]) else     return 0 end ";
    private ThreadLocal<String> lockFlag = new ThreadLocal();

    @Resource
    private RedisTemplate redisTemplate;

    public boolean lock(String key, long expire, int retryTimes, long sleepMillis) {
        boolean result;
        for(result = this.setRedis(key, expire); !result && retryTimes-- > 0; result = this.setRedis(key, expire)) {
            try {
                log.debug("get redisDistributeLock failed, retrying..." + retryTimes);
                Thread.sleep(sleepMillis);
            } catch (InterruptedException var9) {
                log.warn("Interrupted!", var9);
                Thread.currentThread().interrupt();
            }
        }

        return result;
    }

    private boolean setRedis(final String key, final long expire) {
        try {
            boolean status = (Boolean)this.redisTemplate.execute((RedisCallback) (connection) -> {
                String uuid = UUID.randomUUID().toString();
                this.lockFlag.set(uuid);
                byte[] keyByte = this.redisTemplate.getStringSerializer().serialize(key);
                byte[] uuidByte = this.redisTemplate.getStringSerializer().serialize(uuid);
                boolean result = connection.set(keyByte, uuidByte, Expiration.from(expire, TimeUnit.MILLISECONDS), SetOption.ifAbsent());
                return result;
            });
            return status;
        } catch (Exception var5) {
            log.error("set redisDistributeLock occured an exception", var5);
            return false;
        }
    }

    public boolean releaseLock(String key) {
        try {
            Boolean result = (Boolean)this.redisTemplate.execute((RedisCallback) (connection) -> {
                byte[] scriptByte = this.redisTemplate.getStringSerializer().serialize(UNLOCK_LUA);
                return (Boolean)connection.eval(scriptByte, ReturnType.BOOLEAN, 1, new byte[][]{this.redisTemplate.getStringSerializer().serialize(key), this.redisTemplate.getStringSerializer().serialize(this.lockFlag.get())});
            });
            boolean var3 = result;
            return var3;
        } catch (Exception var7) {
            log.error("release redisDistributeLock occured an exception", var7);
        } finally {
            this.lockFlag.remove();
        }

        return false;
    }
}
